-- Parsec
-- Module 'rooms'
require "sprites"
require "theme"
rooms = {}

local function normalize_arg(o)
  local t = type(o);
  if t == "string" or t == "function" then
    local dsc = o;
    o = { dsc = dsc };
  end
  return o;
end

function timer_(time)
  return function()
    timer:set(time);
  end
end

function timerstop()
  timer:stop();
end

function pausescene(o)
  local enter = o.enter;
  o.enter = function(s)
    if enter ~= nil then
      rcall(enter,s);
    end
    timer:set(o.time);
  end
  o.timer = function(s)
    timer:stop();
    if s.ontimer ~= nil then
      s:ontimer(s);
    end
  end
  return scene(o);
end

function hideinput()
  theme.set("inv.y", 800);
end
function showinput()
  theme.set("inv.y", 540);
end

function pause(o)
  local enter = o.enter;
  if o.nam == nil then
    o.nam = function(s)
      if s.bg ~= nil then
        theme.set("scr.gfx.bg", "gfx/"..s.bg..".jpg");
        return nil;
      end
    end;
  end
  local pic = o.pic;
  o.pic = drawing.sprite_blank(800, 600, true);
  o.enter = function(s)
    s:clean();
    if enter ~= nil then
      rcall(enter,s);
    end
    if pic ~= nil then
      local t = sprite.load("gfx/"..pic..".jpg");
      sprite.copy(t, s.pic, 0, 0);
      sprite.free(t);
    end
    timer:set(o.time);
  end
  o.clean = function(s)
    drawing.clean(s.pic, 0, 0, 800, 600);
  end
  o.timer = function(s)
    timer:stop();
    if type(o.next) == "function" then
      o:next();
    else
      walk_(o.next)();
    end
  end
  o.noparser = true;
  return room(o);
end

function gfxroom(o)
  if o.nam == nil then
    o.nam = function(s)
      if s.bg ~= nil then
        bg = s.bg;
        theme.set("scr.gfx.bg", "gfx/"..bg..".jpg");
        return nil;
      end
    end
  end
  o.noparser = true;
  o.pic = nvl(o.pic,drawing.sprite_blank(800, 600, true));
  o.timer = function(s)
    if s._frames == nil then
      s._frames = 0;
    end
    s._frames = s._frames + 1;
    if s.stop ~= nil and s.stop > 0 and s._frames == s.stop then
      s:dispose();
      if s.next ~= nil and type(s.next) == "function" then
        return s:next();
      else
        return walk(s.next);
      end
    end
    if s.ontimer ~= nil then
      local x,y = mouse_pos();
      if not s.nodirect then
        s.pic = sprite.screen();
      end
      s:ontimer(x,y);
    end
  end
  local enter = o.enter;
  o.hideinv = true;
  o.clean = nvl(o.clean,function(s)
    drawing.clean(s.pic, 0, 0, 800, 600);
  end)
  o.enter = function(s,f)
    if not s.nodirect then
      theme.gfx.mode("direct");
      s.pic = sprite.screen();
    end
    s.stop = rcall(s.stop,s);
    s:clean();
    if s.rate ~= nil and s.rate > 0 then
      timer:set(s.rate);
    end
    if enter ~= nil then
      enter(s,f);
    end
  end
  o.loadgfx = function(s,pic)
    if s.cache == nil then
      s.cache = sprite.load("gfx/"..pic..".jpg");
    end
    return s.cache;
  end
  o.cleancache = function(s)
    if s.cache ~= nil then
      sprite.free(s.cache);
      s.cache = nil;
    end
  end
  local dispose = o.dispose;
  o.dispose = function(s)
    theme.gfx.reset();
    s:cleancache();
    if s.rate ~= nil and s.rate > 0 then
      s._frames = nil;
      timer:stop();
    end
    if dispose ~= nil then
      dispose(s);
    end
  end
  return room(o);
end

_deletelist = {};
function __aux(y)
  return __pair(nil,y);
end
function __pair(x,y)
  return function(s)
    if s.aux then
      return y;
    else
      return x;
    end
  end
end
function ifpure(o)
  for k,v in pairs(o) do
    if string.char(k:byte(1))=='_' then
      return;
    end
  end
  o.save = nilfn;
end
function rooms.item(o)
  ifpure(o);
  local nam = o.nam;
  local dsc = o.dsc;
  if o.nam ~= nil then
    o.nam = function(s)
      if o.cnd == nil or rcall(o.cnd,s) then
        local vb = get_verb(parser.verbnr);
        local retval = rcall(nam,s);
        if s.articles ~= nil then
          local arr = retval:split("|");
          local a = s.articles[vb];
          if type(a) == "function" then
            a = a(s);
          end
          if a == nil or a == "" then
            a = "";
          else
            a = a .. "\032";
          end
          local finret = "";
          for v in arr do
            if v then
              if v:startsWith("~") then
                finret = finret .. "~" .. a .. v:trimStart("~") .. "|";
              else
                finret = finret .. a .. v .. "|";
              end
            end
          end
          return finret;
        end
        return retval;
      else
        return "";
      end
    end
  else
    o.nam = nilfn;
  end
  if o.articles == nil then
    o.articles = {};
  end
  o.dsc = function(s)
    if o.cnd == nil or rcall(o.cnd,s) then
      local ret = rcall(dsc,s);
      if ret ~= nil and type(ret) == "string" then
        ret = ret:expand(s)
      end
      return ret;
    else
      return nil;
    end
  end
  o.like = function(self,...)
    local args = {...};
    for i,v in ipairs(args) do
      if type(v) == "function" then
        v(self);
      end
    end
    return self;
  end
  return obj(o);
end

function rooms.event(o)
  o = normalize_arg(o);
  local dsc = o.dsc;
  local cnd = o.cnd;
  o._seen = false;
  o.dsc = function(s)
    if (o.cnd == nil or rcall(o.cnd,s)) and not s._seen then
      s._seen = true;
      here()._eventOn = true;
      return rcall(dsc,s);
    else
      here()._eventOn = nil;
    end
  end
  return rooms.item(o);
end

function rooms.dsc(o)
  o = normalize_arg(o);
  o.save=nil;
  return rooms.item(o);
end

item = rooms.item;

function scene(o)
  o.nam = function(s)
    if s.bg ~= nil then
      theme.set("scr.gfx.bg", "gfx/"..s.bg..".jpg");
    end
    showinput();
    return nil;
  end
  local entered = o.entered;
  local dsc = o.dsc;
  o.kbd = function(s,dn,k)
    if k=='f5' then
      stead.menu_toggle("save");
    else
      stead.menu_toggle("load");
    end
  end
  local enter = o.enter;
  o.enter = function(s)
    if s.checkpoint and not s._donecheckpoint then
      set_checkpoint();
      s._donecheckpoint = true;
    end
    if enter ~= nil then
      return enter(s);
    end
  end
  o.entered = function(s)
    if entered ~= nil then
      entered(s);
    end
    s._seen = true;
  end
  o.dsc = function(s)
    local ret = nvl(rcall(s._tmpdsc,s),"");
    if dsc ~= nil and rcall(dsc,s) ~= nil then
      if ret ~= "" then
        return "" .. ret .. "^^" .. rcall(dsc,s);
      else
        return rcall(dsc,s);
      end
    else
      if ret ~= nil and ret ~= "" then
        return "" .. ret .. "";
      else
        return nil;
      end
    end
  end
  if o.norefresh ~= true then
    o.Refresh = nvl(o.Refresh, function(s)
      if s._tmpdsc ~= nil then
        s._tmpdsc = nil;
      end
      if s.newdsc ~= nil then
        return rcall(s.newdsc,s);
      else
        local dd = nvl(rcall(s.dsc,s),"");
        for i,v in ipairs(s.obj) do
          local d = rcall(v.dsc,v);
          if d ~= nil then
            dd = dd .. " " .. d;
          end
        end
        return dd;
      end
    end);
  end
  o.exit = function(s)
    if s._tmpdsc ~= nil then
      s._tmpdsc = nil;
    end
  end
  o.like = function(self,...)
    local args = {...};
    for i,v in ipairs(args) do
      if type(v) == "function" then
        v(self);
      end
    end
    return self;
  end
  o.after_Exam = function(s)
    hero._exams = nvl(hero._exams,0);
    hero._exams=hero._exams+1;
  end
  o.after_Look = o.after_Exam;
  o.after_Wreck = function(s)
    hero._wrecks = nvl(hero._wrecks,0);
    hero._wrecks =hero._wrecks+1;
  end
  o.after_Tear = o.after_Wreck;
  o.after_Attack = function(s)
    hero._attacks = nvl(hero._attacks,0);
    hero._attacks =hero._attacks+1;
  end
  o.after_Pounce=o.after_Attack;
  o.after_Kick=o.after_Attack;
  o.after_Shoot=o.after_Attach;
  o.after_Crack = function(s)
    hero._cracks =nvl(hero._cracks,0);
    hero._cracks=hero._cracks+1;
  end
  o.after_TurnOn=function(s)
    hero._activs = nvl(hero._activs,0);
    hero._activs=hero._activs+1;
  end
  o.after_TurnOff=o.after_TurnOn;
  o.after_Activate=o.after_TurnOn;
  o.after_Move = function(s)
    hero._move = nvl(hero._move,0);
    hero._move=hero._move+1;
  end
  o.after_Spin=o.after_move;
  o.after_Talk= function(s)
    hero._talks = nvl(hero._talks,0);
    hero._talks=hero._talks+1;
  end
  o.after_Listen=o.after_Talk;
  o.after_Reply=o.after_Talk;
  o.after_Think=function(s)
    hero._think=nvl(hero._think,0);
    hero._think=hero._think+1;
  end
  o.after_Recall=o.after_Think;
  o.after_Invent=o.after_Think;
  o.after_Sit=function(s)
    hero._sits=nvl(hero._sits,0);
    hero._sits=hero._sits+1;
  end
  o.after_Lie=function(s)
    hero._lies=nvl(hero._lies,0);
    hero._lies=hero._lies+1;
  end
  o.after_Cry=function(s)
    hero._cry=nvl(hero._cry,0);
    hero._cry=hero._cry+1;
  end
  o.after_TurnAround=function(s)
    hero._around=nvl(hero._around,0);
    hero._around=hero._around+1;
  end
  o.after_Wait=function(s)
    hero._wait=nvl(hero._wait,0);
    hero._wait=hero._wait+1;
  end
  o.after_Refresh=function(s)
    hero._look=nvl(hero._look,0);
    hero._look=hero._look+1;
  end
  o.after_Stand=function(s)
    hero._stands=nvl(hero._stands,0);
    hero._stands=hero._stands+1;
  end
  o.after_Press=function(s)
    hero._press=nvl(hero._press,0);
    hero._press=hero._press+1;
  end
  o.after_Walk=function(s)
    hero._walks=nvl(hero._walks,0);
    hero._walks=hero._walks+1;
  end
  o.after_Approach=o.after_Walk;
  o.after_Take=function(s)
    hero._takes=nvl(hero._takes,0);
    hero._takes=hero._takes+1;
  end
  o.after_TakeFrom=o.after_Take;
  o.after_Throw=function(s)
    hero._throw=nvl(hero._throw,0);
    hero._throw=hero._throw+1;
  end
  return room(o);
end